package com.zpark.evaluate;

import com.zpark.entity.*;

/**
 * 位移速度评估
 */
public class SpeedEvaluate extends Evaluate {
    private double speedThreshold;//速度阈值；规定超过这个值得速度就会认定有风险
    public SpeedEvaluate(double speedThreshold) {
        super(RiskFactor.SPEED);
        this.speedThreshold=speedThreshold;
    }

    @Override
    public void eval(EvaluateData evaluateData, HistoryData historyData, EvaluateReport evaluateReport, EvaluateChain evaluateChain) {

        //1.对位移速度进行评估;把评估结果写入到评估报告中
        boolean isRisk = doEval(evaluateData,historyData);
        evaluateReport.signReport(RiskFactor.SPEED,isRisk);
        //2.让责任链继续执行
        evaluateChain.doChain(evaluateData,historyData,evaluateReport);

    }

    /**
     * 对位移速度进行评估
     * @param evaluateData
     * @param historyData
     * @return
     */
    private boolean doEval(EvaluateData evaluateData, HistoryData historyData) {
        //计算两个点之间的球面距离
        double d =calcDistance(evaluateData.getGeoPoint(),historyData.getLastLoginGeoPoint());

        //计算本次评估数据的时间和上一次成功登录的时间差
        long time = evaluateData.getEvaluateTime() - historyData.getLastLoginTime();//单位是毫秒
        double t = time / 1000.0 / 60 / 60;///以小时为单位的时间差

        //计算速度
        double s = d/t;

        return s>speedThreshold;
    }

    //地球平均半径
    private  double EARTH_RADIUS = 6371;
    private double calcDistance(GeoPoint geoPoint, GeoPoint lastLoginGeoPoint) {


        double originLat = geoPoint.getLatitude();
        double originLon = geoPoint.getLongitude();

        double destinationLat = lastLoginGeoPoint.getLatitude();
        double destinationLon = lastLoginGeoPoint.getLongitude();

        double radLat1 = rad(originLat);
        double radLat2 = rad(destinationLat);
        double a = radLat1 - radLat2;
        double b = rad(originLon) - rad(destinationLon);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
                + Math.cos(radLat1) * Math.cos(radLat2)
                * Math.pow(Math.sin(b / 2), 2)));
        s = s * EARTH_RADIUS;
        // 保留两位小数
        s = Math.round(s * 100d) / 100d;
        s = s * 1000;
        return s;
    }
    private  double rad(double d) {
        return d * Math.PI / 180.0;
    }
}
